package com.d.lib.ui.view.sort;

import com.d.lib.ui.view.AttrUtils;
import com.d.lib.ui.view.LogUtil;
import java.util.List;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.*;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

/**
 * SideBar
 * Created by D on 2017/6/6.
 */
public class SideBar extends Component implements Component.DrawTask,
    Component.EstimateSizeListener, Component.TouchEventListener {
  public final static int TYPE_NORMAL = 0, TYPE_CENTER = 1;
  private final static String[] DEFAULT_LETTERS = {"↑", "☆", "A", "B", "C", "D", "E", "F", "G",
      "H", "I", "J", "K",
      "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "#"};
  private final static int DEFAULT_MAX_COUNT = 29;

  private final String[] mDefaultLetters;
  private final int mDefaultMaxCount;
  private String[] mLetters;
  private int mMaxCount;

  private int mWidth;
  private int mHeight;
  private Rect mRect;
  private RectFloat mRectF;
  private Paint mPaint;
  private Paint mPaintCur;
  private Paint mPaintRect;
  private int mType;
  private int mColorTrans, mColorWhite, mColorBar, mColorRect;
  private int mCount;
  private float mOnepice;
  private int mWidthBar;
  private int mWidthRect;
  private int mRectRadius;
  private float mTextHeight;
  private float mTextLightHeight;
  private boolean mDValid;
  private int mIndex = -1;
  private OnLetterChangedListener mListener;

  public SideBar(Context context) {
    this(context, null);
  }

  public SideBar(Context context, AttrSet attrs) {
    this(context, attrs, null);
  }

  public SideBar(Context context, AttrSet attrs, String defStyleAttr) {
    super(context, attrs, defStyleAttr);

    mType = AttrUtils.getIntFromAttr(attrs, "lib_ui_view_sidebar_type", TYPE_NORMAL);
    mDefaultMaxCount = AttrUtils.getIntFromAttr(attrs, "lib_ui_view_sidebar_maxCount",
        DEFAULT_MAX_COUNT);
    String strLetters = AttrUtils.getStringFromAttr(attrs, "lib_ui_view_sidebar_letters", "");
    if (TextTool.isNullOrEmpty(strLetters)) {
      mLetters = mDefaultLetters = DEFAULT_LETTERS;
    } else {
      mLetters = mDefaultLetters = strLetters.split(";");
    }
    mMaxCount = Math.max(mDefaultMaxCount, mLetters.length);
    LogUtil.debug("sort", " mLetters: " + mLetters.toString() + ", mMaxCount: " + mMaxCount);
    init(context);
    addDrawTask(this::onDraw);
    setEstimateSizeListener(this::onEstimateSize);
    setTouchEventListener(this::onTouchEvent);
  }

  private void init(Context context) {
    if (mType == TYPE_CENTER) {
      mLetters = new String[]{};
    }
    mCount = mLetters.length;
    mWidthRect = AttrHelper.fp2px(70, context);
    mRectRadius = AttrHelper.fp2px(6, context);
    mColorTrans = Color.getIntColor("#00000000");
    mColorWhite = Color.WHITE.getValue();
    mColorBar = Color.getIntColor("#aaBBBBBB");
    mColorRect = Color.getIntColor("#aa7F7F7F");

    mRect = new Rect();
    mRectF = new RectFloat();
    mPaint = new Paint();
    mPaint.setTextAlign(TextAlignment.CENTER);
    mPaint.setColor(new Color(Color.getIntColor("#565656")));

    mPaintCur = new Paint();
    mPaintCur.setTextAlign(TextAlignment.CENTER);
    mPaintCur.setColor(new Color(Color.getIntColor("#008577")));

    mPaintRect = new Paint();
    mPaintRect.setTextAlign(TextAlignment.CENTER);
    mPaintRect.setTextSize(AttrHelper.fp2px(32, context));
  }

  private void resetRect(int left, int top, int right, int bottom, int color) {
    mRect.set(left, top, right, bottom);
    mRectF.modify(mRect);
    mPaintRect.setColor(new Color(color));
  }

  private int adjustIndex(float eY) {
    eY = Math.max(eY, 0);
    eY = Math.min(eY, mHeight);
    int i = (int) (eY / mOnepice);
    i = Math.max(i, 0);
    i = Math.min(i, mCount - 1);
    return i;
  }

  private boolean delegate(int i) {
    if (mDValid && i != mIndex) {
      mIndex = i;
      if (mIndex != -1 && mListener != null) {
        mListener.onChange(mIndex, mLetters[mIndex]);
      }
      invalidate();
      return true;
    }
    return false;
  }

  /**
   *
   * 设置侧边栏类型
   */
  public void setType(int type) {
    mType = type;
  }

  /**
   *
   * 设置侧边栏最大值
   */
  public void setmMaxCount(int count) {
    mMaxCount = count;
  }

  /**
   *
   * 设置侧边栏内容
   */
  public void setmLetters(String[] letters) {
    mLetters = letters;
  }

  public void reset(List<String> datas) {
    if (datas == null) {
      return;
    }
    mLetters = mType == TYPE_CENTER ? datas.toArray(new String[datas.size()])
        : mDefaultLetters;
    mMaxCount = Math.max(mDefaultMaxCount, mLetters.length);
    mCount = mLetters.length;
    LogUtil.debug("sort",
        " mDatas: " + datas.toString() + ", mLetters: " + mLetters.length);
    postLayout();
    invalidate();
  }

  public void setOnLetterChangedListener(OnLetterChangedListener listener) {
    this.mListener = listener;
  }

  @Override
  public void onDraw(Component component, Canvas canvas) {
    if (mType == TYPE_NORMAL) {
      resetRect(mWidth - mWidthBar, 0, mWidth, mHeight, mIndex == -1 ? mColorTrans : mColorBar);
      canvas.drawRect(mRectF, mPaintRect);

      for (int i = 0; i < mCount; i++) {
        canvas.drawText(i == mIndex ? mPaintCur : mPaint, mLetters[i], mWidth - mWidthBar / 2,
            mOnepice * i + mOnepice / 2 + mTextHeight / 2);
      }
      if (mIndex >= 0 && mIndex < mCount) {
        resetRect((mWidth - mWidthRect) / 2, (mHeight - mWidthRect) / 2,
            (mWidth + mWidthRect) / 2, (mHeight + mWidthRect) / 2, mColorRect);
        canvas.drawRoundRect(mRectF, mRectRadius, mRectRadius, mPaintRect);
        mPaintRect.setColor(new Color(mColorWhite));
        canvas.drawText(mPaintRect, mLetters[mIndex], mWidth / 2, (mHeight + mTextLightHeight) / 2);
      }
    } else {
      float offsetY = mHeight * (1 - 1f * mCount / mMaxCount) / 2;
      float endY = offsetY + mOnepice * mCount;

      for (int i = 0; i < mCount; i++) {
        canvas.drawText(i == mIndex ? mPaintCur : mPaint, mLetters[i], mWidth - mWidthBar / 2,
            offsetY + mOnepice * i + mOnepice / 2 + mTextHeight / 2);
      }
    }
    LogUtil.debug("sort", " onDraw mCount: " + mCount + ", mWidth: " + mWidth);
  }

  @Override
  public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
    mWidth = EstimateSpec.getSize(widthMeasureSpec);
    mHeight = EstimateSpec.getSize(heightMeasureSpec);
    mOnepice = 1f * mHeight / mMaxCount;
    mWidthBar = (int) (mOnepice * 1.182f);
    float textSize = mOnepice * 0.686f;
    mPaint.setTextSize((int) textSize);
    mPaintCur.setTextSize((int) textSize);
    mTextHeight = getTextHeight(mPaint);
    mTextLightHeight = getTextHeight(mPaintRect);
    setEstimatedSize(EstimateSpec.getSizeWithMode(mWidth, EstimateSpec.PRECISE),
        EstimateSpec.getSizeWithMode(mHeight, EstimateSpec.PRECISE));
    LogUtil.debug("sort", " onEstimateSize mWidth: " + mWidth + ", mHeight: " + mHeight);
    return true;
  }

  @Override
  public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
    float offsetY = mType == TYPE_CENTER ? mHeight * (1 - 1f * mCount / mMaxCount) / 2 : 0;
    float eX = touchEvent.getPointerPosition(touchEvent.getIndex()).getX();
    float eY = touchEvent.getPointerPosition(touchEvent.getIndex()).getY() - offsetY;
    switch (touchEvent.getAction()) {
      case TouchEvent.PRIMARY_POINT_DOWN:
        mDValid = eY >= 0 && eY <= mOnepice * mCount + 1 && eX > mWidth - mWidthBar;
        return mDValid && delegate(adjustIndex(eY));
      case TouchEvent.POINT_MOVE:
        return delegate(adjustIndex(eY));
      case TouchEvent.CANCEL:
      case TouchEvent.PRIMARY_POINT_UP:
        return delegate(-1);
    }
    return true;
  }

  public interface OnLetterChangedListener {
    void onChange(int index, String c);
  }

  /**
   * Get font height
   */
  public static float getTextHeight(Paint p) {
    Paint.FontMetrics fm = p.getFontMetrics();
    return (float) ((Math.ceil(fm.descent - fm.top) + 2) / 2);
  }

  public static int getTextWidth(String str, Paint paint) {
    Rect bounds = new Rect();
    paint.getTextBounds(str);
    return bounds.getWidth();
  }
}
